package com.knowledge.plus.缓存.controller;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * - @Cacheable  {@link CacheDemoController#findBook(String, String)}
 * - @CacheEvict {@link CacheDemoController#delete(Long, Object)}
 * - @CachePut   {@link CacheDemoController#update(Long, Object)}
 *
 * @author aFei
 * @since 2024/7/18
 */
@Controller
@RestController
public class CacheDemoController {

    /**
     * 示例：浏览器调用 http://localhost:8889/cache?isbn=555
     * findBookByIsbn 方法的结果会被缓存到名为 cache_name:info_name 的缓存中，缓存的 key 是方法的参数 isbn
     */
    @GetMapping("cache")
    @Cacheable(cacheNames = "cache_name:info_name", key = "#isbn", condition = "#key != null")
    public String findBookByIsbn(String isbn) {
        // 模拟查询数据库或执行复杂计算
        System.out.println("do something");
        return isbn;
    }

    @GetMapping("books")
    @Cacheable(value = "books", key = "#root.methodName + ':' + #id + ':' + #author", condition = "#key != null")
    public String findBook(String id, String author) {
        // 实现查找逻辑
        return "success_success";
    }

    /**
     * 注解 @CacheEvict 是 Spring Cache注解之一，用于指示在方法执行后应清除缓存。
     * 用途：
     * - 清除缓存中的条目，通常在更新或删除数据库中的数据之后使用。
     * - 可以防止缓存与数据库中的数据不一致的情况发生。
     *
     * 注意：使用 @CacheEvict 时，不需要关心方法的返回值，因为它的目的是清除缓存中的条目。
     * 示例：http://localhost:8889/update?isbn=555
     *
     * @param isbn 要更新的用户的ID。这是缓存键的一部分，用于精确定位要清除的缓存条目。
     */
    // value属性指定了缓存的名称，key属性指定了要清除的缓存项的键
    // #isbn表示使用方法参数isbn作为缓存键的一部分
    @PostMapping("delete")
    @CacheEvict(value = "cache_name:info_name", key = "#isbn", condition = "#key != null")
    public void delete(Long isbn, Object dto) {
        // userRepository.updateUser(userId, updatedUser);
        System.out.println("执行'cache'接口会生成缓存，运行此方法时缓存被清除");
    }

    /**
     * 当带有 @CachePut 注解的方法被调用时，其返回值会被用来更新缓存中的条目。如果该条目的键对应的缓存条目不存在，则创建新的缓存条目
     * 用途：
     * - 更新缓存中的条目，通常在更新数据库中的数据之后使用。
     * - 保证缓存与数据库中的数据保持一致。
     *
     * 注意：@CachePut 方法必须有返回值，并且这个返回值将被存储到缓存中。
     */
    @PostMapping("update")
    @CachePut(value = "cache_name:info_name", key = "#isbn", condition = "#key != null")
    public String update(Long isbn, Object dto) {
        // 更新用户信息的逻辑
        // userRepository.updateUser(userId, updatedUser);
        return "Congratulation !" + isbn;
    }

}
